package grape.workflow.rest.form;

import grape.common.tools.ToolService;
import grape.workflow.rest.form.vo.FormTypeVo;
import grape.workflow.service.form.enums.FormType;
import org.apache.commons.lang3.StringUtils;
import org.flowable.app.api.AppRepositoryService;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.engine.*;
import org.flowable.engine.form.StartFormData;
import org.flowable.engine.form.TaskFormData;
import org.flowable.engine.impl.form.FormHandlerHelper;
import org.flowable.engine.impl.form.TaskFormHandler;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.form.api.FormInfo;
import org.flowable.form.api.FormRepositoryService;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.service.HistoricTaskService;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
import org.flowable.ui.common.service.exception.NotFoundException;
import org.flowable.ui.task.service.runtime.FlowableProcessDefinitionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 获取form的类型
 * Created by yangwei
 * Created at 2020/6/28 16:48
 */
@Component
public class FormTypeHelper implements ToolService {
    @Autowired
    private FormService formService;

    @Autowired
    protected RepositoryService repositoryService;

    @Autowired
    protected ProcessEngineConfiguration processEngineConfiguration;

    @Autowired
    protected AppRepositoryService appRepositoryService;

    @Autowired
    protected FormRepositoryService formRepositoryService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService  historyService;

    /**
     * 任务表单类型
     * @param taskId
     * @return
     */
    public FormTypeVo getTaskFormTypeVo(String taskId){
        FormTypeVo formTypeVo = new FormTypeVo();
        TaskInfo task = taskService.createTaskQuery().taskId(taskId).singleResult();
        boolean isRuntimeTask = true;
        if (task == null) {
            task = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
            isRuntimeTask = false;
        }
        formTypeVo.setFormKey(task.getFormKey());
        if(!isStrEmpty(task.getFormKey())){
            try {
                FormInfo taskFormModel = taskService.getTaskFormModel(taskId);
                formTypeVo.setType(FormType.relation.getType());
                formTypeVo.setTypeName(FormType.relation.getName());
            } catch (FlowableObjectNotFoundException e) {
                formTypeVo.setType(FormType.normal.getType());
                formTypeVo.setTypeName(FormType.normal.getName());
            }
        }else {
            if (isRuntimeTask) {
                // 历史任务这里获取不到
                TaskFormData taskFormData = formService.getTaskFormData(taskId);
                if (taskFormData != null && !isEmpty(taskFormData.getFormProperties())) {
                    formTypeVo.setType(FormType.dynamic.getType());
                    formTypeVo.setTypeName(FormType.dynamic.getName());
                }
            }else {
                List<FormProperty> formProperties = taskModelFormProperties(task);
                if (formProperties != null && !isEmpty(formProperties)) {
                    formTypeVo.setType(FormType.dynamic.getType());
                    formTypeVo.setTypeName(FormType.dynamic.getName());
                }
            }
        }
        return formTypeVo;
    }

    /**
     * 表单在定义中定义的
     * @param task
     * @return
     */
    public List<FormProperty> taskModelFormProperties(TaskInfo task) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
        Process process = bpmnModel.getProcessById(definition.getKey());
        FlowElement flowElement = process.getFlowElement(task.getTaskDefinitionKey(), true);
        if (flowElement instanceof UserTask) {
            UserTask userTask = (UserTask) flowElement;
            List<FormProperty> formProperties = userTask.getFormProperties();
            return formProperties;
        }
        return null;
    }
    /**
     * 启动表单类型
     * @param definition
     * @return
     */
    public FormTypeVo getStartFormTypeVo(ProcessDefinition definition){
        FormTypeVo formTypeVo = new FormTypeVo();
        assertParamNotNull(definition,"definition不能为空");

        if (definition.hasStartFormKey()) {
            String startFormKey = formService.getStartFormKey(definition.getId());
            formTypeVo.setFormKey(startFormKey);
            try {
                FormInfo startForm = getStartFormDependFormKey(definition);
                formTypeVo.setType(FormType.relation.getType());
                formTypeVo.setTypeName(FormType.relation.getName());
            } catch (NotFoundException | FlowableObjectNotFoundException ne) {
                formTypeVo.setType(FormType.normal.getType());
                formTypeVo.setTypeName(FormType.normal.getName());
            }

        }else{
            StartFormData startFormData = formService.getStartFormData(definition.getId());
            if (startFormData != null && !isEmpty(startFormData.getFormProperties())) {
                formTypeVo.setType(FormType.dynamic.getType());
                formTypeVo.setTypeName(FormType.dynamic.getName());
            }
        }
        return formTypeVo;
    }

    /**
     * 启动表单 存在表单key的时候且已部署表单会有值
     * 该方法来自{@link FlowableProcessDefinitionService#getStartForm(org.flowable.engine.repository.ProcessDefinition)}
     * @param processDefinition
     * @return
     */
    public FormInfo getStartFormDependFormKey(ProcessDefinition processDefinition) {
        FormInfo formInfo = null;
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        Process process = bpmnModel.getProcessById(processDefinition.getKey());
        FlowElement startElement = process.getInitialFlowElement();
        if (startElement instanceof StartEvent) {
            StartEvent startEvent = (StartEvent) startElement;
            if (StringUtils.isNotEmpty(startEvent.getFormKey())) {
                Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(processDefinition.getDeploymentId()).singleResult();
                formInfo = formRepositoryService.getFormModelByKeyAndParentDeploymentId(startEvent.getFormKey(), deployment.getParentDeploymentId(),
                        processDefinition.getTenantId(), processEngineConfiguration.isFallbackToDefaultTenant());
            }
        }

        if (formInfo == null) {
            // Definition found, but no form attached
            throw new NotFoundException("Process definition does not have a form defined: " + processDefinition.getId());
        }

        return formInfo;
    }
}
